/*
qnettest - Qt4 application for testing network performance
Copyright (C) 2007  Pyry Haulos

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

#include <QtCore>
#include <QtNetwork>
#include "tcpclient.hpp"
#include "tcpproto.hpp"

TcpClient::TcpClient(TcpClientArgs *args)
{
	this->args = args;
	out = args->outStream;

	helpers = new QVector <TcpClientHelper *>;
	testdata = TcpProto::generateTestData(args->send_bytes);	// lets guess send_size is bigger
	active_helpers = 0;
}

TcpClient::~TcpClient()
{
	delete helpers;
	TcpProto::freeTestData(testdata);
}

bool TcpClient::start()
{
	TcpClientHelper *helper;

	helper_reports = new qint32[args->simult_num];
	helper_reports_i = 0;

	time = new QTime;
	time->start();

	for (qint32 i = 0; i < args->simult_num; i++) {
		helper_reports[i] = -1;
		helper = new TcpClientHelper(args, testdata, this);
		active_helpers++;

		connect(helper, SIGNAL(finished()), this, SLOT(helperFinished()));
		connect(helper, SIGNAL(finished()), helper, SLOT(deleteLater()));
		connect(helper, SIGNAL(report(qint32)), this, SLOT(addHelperReport(qint32)));
		// connect( helper, SIGNAL( error( QTcpSocket::SocketError ) ), this, SLOT( showSocketError( QTcpSocket::SocketError ) ) );

		helper->start();
		helpers->push_back(helper);
	}

	return true;
}

void TcpClient::helperFinished()
{
#ifdef TCPCLIENT_DEBUG
	qDebug() << "TcpClient::helperFinished()";
#endif
	active_helpers--;

	if (active_helpers == 0)
		showReport();
}

void TcpClient::addHelperReport(qint32 packet_count)
{
	helper_reports[helper_reports_i] = packet_count;

	helper_reports_i++;
}

void TcpClient::showReport()
{
	float actual_time = (float) time->elapsed();
	actual_time = actual_time / 1000.0f;
	delete time;

	float est_avg_up_bps = (1000.0f / (float) args->interval) * (float) (args->send_bytes);
	float est_avg_down_bps = (1000.0f / (float) args->interval) * (float) (args->recv_bytes);
	float est_total_up_bps = est_avg_up_bps * (float) args->simult_num;
	float est_total_down_bps = est_avg_down_bps * (float) args->simult_num;

	float avg_packets = 0.0;
	quint32 total_packets = 0;
	quint32 failed_threads = 0;

	float avg_up_bps = 0.0f;
	float avg_down_bps = 0.0f;
	float total_up_bps = 0.0f;
	float total_down_bps = 0.0f;

	qint32 value;
	for (qint32 i = 0; i < args->simult_num; i++) {
		value = helper_reports[i];

		if (value < 0) {
			failed_threads++;
			continue;
		}

		avg_packets += (float) value / (float) args->simult_num;
		total_packets += value;
	}

	avg_up_bps = (avg_packets * (float) args->send_bytes) / actual_time;
	avg_down_bps = (avg_packets * (float) args->recv_bytes) / actual_time;
	total_up_bps = ((float) total_packets * (float) args->send_bytes) / actual_time;
	total_down_bps = ((float) total_packets * (float) args->recv_bytes) / actual_time;

	*out << QObject::tr("total upstream was %1 KB/s (%2\% of estimated %3 KB/s)").arg(total_up_bps / 1024.0).arg(100.0 * (total_up_bps / est_total_up_bps)).arg(est_total_up_bps / 1024.0) << endl;
	*out << QObject::tr("total downstream was %1 KB/s (%2\% of estimated %3 KB/s)").arg(total_down_bps / 1024.0).arg(100.0 * (total_down_bps / est_total_down_bps)).arg(est_total_down_bps / 1024.0) << endl;

	*out << QObject::tr("average upstream was %1 KB/s (%2\% of estimated %3 KB/s)").arg(avg_up_bps / 1024.0).arg(100.0 * (avg_up_bps / est_avg_up_bps)).arg(est_avg_up_bps / 1024.0) << endl;
	*out << QObject::tr("average downstream was %1 KB/s (%2\% of estimated %3 KB/s)").arg(avg_down_bps / 1024.0).arg(100.0 * (avg_down_bps / est_avg_down_bps)).arg(est_avg_down_bps / 1024.0) << endl;

	if (failed_threads > 0)
		*out << QObject::tr("%1 threads failed").arg(failed_threads) << endl;

	emit finished();
}
